﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Phoenix.ActionResults;
using Phoenix.Framework;
using Phoenix.Tests.Controllers;
using Xunit;

namespace Phoenix.Tests.Framework
{
    public class ControllerActionExpressionParserTests
    {
        readonly ClassWithProperty field = new ClassWithProperty();

        [Fact]
        public void parser_gets_actionname_for_action_with_no_params()
        {
            // arrange
            Expression<Func<TestController, ActionResult>> expression = c => c.TestAction();
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression);

            // act
            var action = parser.ActionName;

            // assert
            Assert.Equal("TestAction", action);
        }

        [Fact]
        public void parser_gets_parameter_for_action_with_one_param()
        {
            // arrange
            Expression<Func<TestController, ActionResult>> expression = c => c.TestAction(5);
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression);

            // act
            var action = parser.ActionName;

            // assert
            Assert.Equal("TestAction", action);
            Assert.Equal("arg", parser.GetNavigationParameters()[0].Name);
            Assert.Equal(5, parser.GetNavigationParameters()[0].Value);
        }

        [Fact]
        public void parser_gets_parameter_for_action_with_one_nested_param()
        {
            // arrange
            Expression<Func<TestController, ActionResult>> expression = c => c.TestAction(C.Prop);
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression);

            // act
            var action = parser.ActionName;

            // assert
            var controllerActionParameters = parser.GetNavigationParameters();
            Assert.Equal("TestAction", action);
            Assert.Equal("arg", controllerActionParameters[0].Name);
            Assert.Equal(7, controllerActionParameters[0].Value);
        }

        public ClassWithProperty C
        {
            get { return new ClassWithProperty {Prop = 7}; }
        }

        [Fact]
        public void parser_gets_parameter_for_action_with_two_deep_nested_param()
        {
            // arrange
            Expression<Func<TestController, ActionResult>> expression = c => c.TestAction(C2.SubClass.SubProp);
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression);

            // act
            var action = parser.ActionName;

            // assert
            var controllerActionParameters = parser.GetNavigationParameters();
            Assert.Equal("TestAction", action);
            Assert.Equal("arg", controllerActionParameters[0].Name);
            Assert.Equal(42, controllerActionParameters[0].Value);
        }

        public ClassWithProperty C2
        {
            get { return new ClassWithProperty { SubClass = new SubClass{ SubProp = 42 } }; }
        }

        [Fact]
        public void parser_gets_parameter_for_action_with_one_arg_and_one_param()
        {
            // arrange
            Expression<Func<TestController, int, ActionResult>> expression = (c, a) => c.TestAction(a);
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression, 3);

            // act
            var action = parser.ActionName;
            var controllerActionParameter = parser.GetNavigationParameters()[0];

            // assert
            Assert.Equal("TestAction", action);
            Assert.Equal("arg", controllerActionParameter.Name);
            Assert.Equal(3, controllerActionParameter.Value);
        }

        [Fact]
        public void parser_gets_parameter_for_action_with_one_arg_and_one_param_prop_on_class()
        {
            // arrange
            Expression<Func<TestController, ClassWithProperty, ActionResult>> expression = (c, a) => c.TestAction(a.Prop, a.List);
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression, new ClassWithProperty{Prop = 3, List = new List<string>{ "Stuff" }});

            // act
            var action = parser.ActionName;
            var controllerActionParameters = parser.GetNavigationParameters();
            var controllerActionParameter = controllerActionParameters[0];

            // assert
            Assert.Equal("TestAction", action);
            Assert.Equal("arg", controllerActionParameter.Name);
            Assert.Equal(3, controllerActionParameter.Value);
        }

        [Fact]
        public void parser_can_parse_nullable_guid()
        {
            // arrange
            field.Id = Guid.NewGuid();
            Expression<Func<TestController, ActionResult>> expression = c => c.GetFoo(field.Id.Value);
            var parser = new ControllerActionExpressionParser(expression.Body as MethodCallExpression);

            // act
            var action = parser.ActionName;

            // assert
            Assert.Equal("GetFoo", action);
            Assert.Equal("value", parser.GetNavigationParameters()[0].Name);
            Assert.Equal(field.Id, parser.GetNavigationParameters()[0].Value);
        }

        public class ClassWithProperty
        {
            public Guid? Id { get; set; }

            public int Prop { get; set; }

            public List<string> List { get; set; }

            public SubClass SubClass { get; set; }
        }

        public class SubClass
        {
            public int SubProp { get; set; }
        }
    }
}